package com.ytf.test.third;

import sun.misc.DoubleConsts;

/**
 * @author: YTF
 * @date: 2024/9/13 16:46
 * @version: 1.0
 * @description: 四舍五入
 */
public class RoundingNumbers {
    public static void main(String[] args) {
        double above = 0.7, below = 0.4;
        float fAbove = 0.7f, fBelow = 0.4f;
        System.out.println("above:"+above+" Math.round(above):"+Math.round(above));
        System.out.println("below:"+below+" Math.round(below):"+Math.round(below));
        System.out.println("fAbove:"+fAbove+" Math.round(fAbove):"+Math.round(fAbove));
        System.out.println("fBelow:"+fBelow+" Math.round(fBelow):"+Math.round(fBelow));
        /**
         * Output:
         * above:0.7 Math.round(above):1
         * below:0.4 Math.round(below):0
         * fAbove:0.7 Math.round(fAbove):1
         * fBelow:0.4 Math.round(fBelow):0
         * 四舍五入需要使用Mach类中的方法
         */
        System.out.println("above:"+above+" round(above):"+round(2.4));
    }

    public static long round(double a) {
        System.out.println("输入: "+a);
        //将一个 double 类型的值转换为 long 类型的原始位表示。这个方法返回的是该 double 值的二进制表示形式，其中包含了符号位、指数位和尾数位。
        long longBits = Double.doubleToRawLongBits(a);
        // longBits:4613037098315599053
        System.out.println("longBits:"+longBits+" Binary:"+Long.toBinaryString(longBits));
        // DoubleConsts.EXP_BIT_MASK : 9218868437227405312L 表示 double 类型数值的指数部分的掩码。
        Long dis1 = (longBits & DoubleConsts.EXP_BIT_MASK);
        System.out.println("dis1: "+dis1+" Binary:"+Long.toBinaryString(dis1));
        // DoubleConsts.SIGNIFICAND_WIDTH : 53  表示 double 类型数值的尾数部分的宽度
        int dis2 = (DoubleConsts.SIGNIFICAND_WIDTH - 1);
        long biasedExp = dis1 >> dis2;
        System.out.println("biasedExp: "+biasedExp);
        /*
            表示 double 类型数值的指数部分的偏移量。
            在 Java 中，double 类型的数值由三部分组成：符号位、指数位和尾数位。
            DoubleConsts.EXP_BIAS : 1023，表示指数部分的实际值需要加上这个偏移量才能得到实际的指数值。
            例如，如果一个 double 类型的数值的指数部分是 1023，那么它的实际指数值为 0；如果指数部分是 1024，那么它的实际指数值为 1。
        */
        int dis3 = (DoubleConsts.SIGNIFICAND_WIDTH - 2 + DoubleConsts.EXP_BIAS);
        System.out.println("dis3: "+dis3);
        long shift = dis3 - biasedExp;
        long dis4 =(shift & -64);
        System.out.println("dis4: "+dis4);
        if (dis4 == 0) {
            // DoubleConsts.SIGNIF_BIT_MASK :4503599627370495L  是一个常量，表示 double 类型数值的尾数部分的掩码。
            long dis5 =(longBits & DoubleConsts.SIGNIF_BIT_MASK);
            System.out.println("dis5: "+dis5+" Binary:"+Long.toBinaryString(dis5));
            long r = (dis5 | (DoubleConsts.SIGNIF_BIT_MASK + 1));
            System.out.println("r: "+r+" Binary:"+Long.toBinaryString(r));
            if (longBits < 0) {
                r = -r;
                System.out.println("-r: "+r+" Binary:"+Long.toBinaryString(r));
            }
            long dis6 = (r >> shift);
            System.out.println("dis6: "+dis6);
            long dis7 = dis6+1;
            System.out.println("dis7: "+dis7);
            long dis8 = dis7 >>1;
            System.out.println("dis8: "+dis8);
            return dis8;
        } else {
            return (long) a;
        }
        /**
         * Output:
         * 输入: 2.5
         * longBits:4612811918334230528 Binary:100000000000100000000000000000000000000000000000000000000000000
         * dis1: 4611686018427387904 Binary:100000000000000000000000000000000000000000000000000000000000000
         * biasedExp: 1024
         * dis3: 1074
         * dis4: 0
         * dis5: 1125899906842624 Binary:100000000000000000000000000000000000000000000000000
         * r: 5629499534213120 Binary:10100000000000000000000000000000000000000000000000000
         * dis6: 5
         * dis7: 6
         * dis8: 3
         * above:0.7 round(above):3
         *
         * 输入: 2.4
         * longBits:4612586738352862003 Binary:100000000000011001100110011001100110011001100110011001100110011
         * dis1: 4611686018427387904 Binary:100000000000000000000000000000000000000000000000000000000000000
         * biasedExp: 1024
         * dis3: 1074
         * dis4: 0
         * dis5: 900719925474099 Binary:11001100110011001100110011001100110011001100110011
         * r: 5404319552844595 Binary:10011001100110011001100110011001100110011001100110011
         * dis6: 4
         * dis7: 5
         * dis8: 2
         *
         * 总结：
         *  第一步变成二进制
         *  第二步得到实际指数
         *  第三步得出最终结果
         *  两个原理：
         *      1.二进制逢二进一。
         *      2.小数的二进制计算方法采用乘2取整法。0.4 转换二进制首位不是1 0.5转换二进制首位是1
         *  这样就可以四舍五入了
         */
    }

}
